<?php
/*
 * This file is part of the BooXtore Student project.
 *
 * (c) Francis Backeland f.backeland@gmail.com
 * (c) Laurine Chaplot chaplot.laurine@orange.fr
 * (c) Julien Dutot julien.dutot@gmail.com
 * (c) Romain Guillaume romain-guillaume@orange.fr
 * (c) Guillaume Paringaux g.paringaux@gmail.com
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code
 */

namespace BXTR\AdminBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form;
use BXTR\BookBundle\Entity\BookCategory;
use BXTR\AdminBundle\Form\Type\BookCategoryType;
use BXTR\AdminBundle\Form\Type\BookCategoryListType;

/**
 * Management of the BookCategory entity. 
 */
class BookCategoryController extends Controller
{
    /** 
     * Display a list of categories.
     * From the list we can add a new category, remove or edit the selected
     * category or go back to the administation index.
     */
    public function listAction(Request $request)
    {
        // fetch list
        $em = $this->getDoctrine()->getManager();
        $categories = $em->getRepository('BXTRBookBundle:BookCategory')
            // Optimized query, save n query (n = #category) because we use the getter booksCount in the table.
            ->findAllJoinedToBooks();

        // build list and action buttons.
        // the BookCategoryListType defines the fields and labels for the table
        $form = $this->createFormBuilder()
            ->add('list', new BookCategoryListType(), Array(
                'collection' => $categories,
            ))
            ->add('back', 'back_button', array(
                'url' => $this->generateUrl('bxtr_admin_index')
            ))
            // back button disable validation by default
            ->add('add', 'add_button')
            ->add('delete', 'remove_button', array(
                'datatables_selector' => true,
            ))
            ->add('edit', 'edit_button', array(
                'datatables_selector' => true,
            ))
            ->getForm();

        $form->handleRequest($request);

        if ($form->isValid()) {
            // test wich button is clicked and apply redirects
            if ($form->get('add')->isClicked()) {

                return $this->redirect($this->generateUrl('bxtr_admin_category_add'));
            } 
            if ($form->get('edit')->isClicked()) {
                $selectedCategory = $form->get('list')->getData();

                return $this->redirect($this->generateUrl('bxtr_admin_category_edit', Array('id' => $selectedCategory->getId())));
            } elseif ($form->get('delete')->isClicked()) {
                $selectedCategory = $form->get('list')->getData();

                return $this->redirect($this->generateUrl('bxtr_admin_category_delete', Array('id' => $selectedCategory->getId())));
            }
        }
        
        // Display view
        $trans = $this->get('translator');
        return $this->render('BXTRAdminBundle:Layout:List.html.twig', Array(
            'form' => $form->createView(),
            'main_title' => $trans->trans('Ent.BookCategory.List')
        ));
    }

    /** 
     * Display a new category record for edition.
     */
    public function addAction(Request $request) 
    {
        return $this->buildEditForm($request);
    }

    /**
     * Display a delete confirmation page.
     *
     * If the category have books associated, the user can shift the books to another
     * category with a button or remove the category AND the books.
     *
     * If no books are associated to the category, only the remove button is shown and
     * the page act as a confirmation page.
     *
     * @param Request $request
     * @param mixed $id
     */
    public function deleteAction(Request $request, $id) 
    {
        // Fetch entities
        $em = $this->getDoctrine()->getManager();
        try {
            $fromCategory = $em->getRepository('BXTRBookBundle:BookCategory')
                // ->findOneById($id); would work, saves 1 query
                ->findOneByIdJoinedToBooks($id);
        } catch ( \Doctrine\ORM\NoResultException $e) {
            throw new \Exception("Unknown Id");
        }
        // Begin form building
        $builder = $this->createFormBuilder();
        
        $trans = $this->get('translator');

        // Message displayed by the view.
        $message = null;

        // If the form has book, get the list of avaiable categories , add
        // it to the form along with the selection button and set a specific message.
        // Else set another message.
        $shiftable = false;
        if ($fromCategory->getBooks()->count() > 0) {
            $shiftable = true;
            // Fetch entities for the list
            $categories = $em->getRepository('BXTRBookBundle:BookCategory')
                ->findAllJoinedToBooksWithoutCategory($fromCategory);

            // Add list and selection buttons.
            $builder
                ->add('category_selection', new BookCategoryListType(), Array(
                    'collection' => $categories,
                    'constraints' => array(
                        new NotBlank(),
                    )
                ));
            
            $message = $trans->trans('Ent.BookCategory.CanShift', Array(
                '%name%' => $fromCategory->getName(),
                '%nb_book%' => $fromCategory->getBooksCount()
            ));
        } else {
            $message = $trans->trans('Ent.BookCategory.ConfirmDelete', Array(
                '%name%' => $fromCategory->getName()
            ));
        }

        // Finish form building by adding remove and back buttons.
        $form = $builder
            ->add('delete', 'remove_button', Array(
               'label' => 'Form.Delete',
               'icon' => 'warning-sign'
            ))
            ->add('back', 'back_button', array(
                'url' => $this->generateUrl('bxtr_admin_category_list')
            ))
            ->getForm();

        $form->handleRequest($request);

        if($form->isValid()) {
            // Test wich button is clicked and redirect acordingly.

            // if a shift is required, change the category of the books.
            // after remove the category and redirect the user to the list.
            if ($shiftable) {
                $selectedCategory = $form->get('category_selection')->getData();

                // Test if the categories are different.
                if ($selectedCategory == $fromCategory) {
                    throw new \Exception("The source and destination categories can't match");
                }

                foreach($fromCategory->getBooks() as $book) {
                    $book->setCategory($selectedCategory);
                    $em->persist($book);
                }
                $em->persist($selectedCategory);
            } else {
                // @TODO remove books or set them orphans
                //foreach($fromCategory->getBooks() as $book) {
                //    $book->setCategory(null);
                //    $em->persist($book);
                //}
            }
            $em->remove($fromCategory);
            $em->flush();

            return $this->redirect($this->generateUrl('bxtr_admin_category_list'));
        } 
        
        return $this->render('BXTRAdminBundle:Layout:Delete.html.twig', array(
            'form' => $form->createView(),
            'main_title' => 'Suppression de la catégorie "' . $fromCategory->getName() . '"',
            'message' => $message,
        ));
    }

    /**
     * Display an edit form
     *
     * @param Request $request
     * @param mixed $id
     */
    public function editAction(Request $request, $id)
    {
        $em = $this->getDoctrine()->getManager();
        $category = $em->getRepository('BXTRBookBundle:BookCategory')->findOneById($id);

        if (!$category) {
            throw new \Exception("Unknown Id");
        }
        
        return $this->buildEditForm($request, $category);
    }

    /**
     * Build the add or edit form.
     * A simple field list with a back and save button.
     *
     * @param Request $request
     * @param BookCategory $category
     */
    protected function buildEditForm(Request $request, BookCategory $category=null) {
        $add = false;
        if ($category === null) {
            $category = new BookCategory();
            $add = true;
        }
        // The BookCategoryType form create a list of fields and a save and back buttons.
        $form = $this->createFormBuilder($category)
            ->add('name', null, Array(
                'label' => 'Ent.Default.Fields.Name'
            ))
            ->add('save', 'save_button')
            ->add('back', 'back_button', array(
                'url' => $this->generateUrl('bxtr_admin_category_list')
            ))
            ->getForm();

        $form->handleRequest($request);

        if($form->isValid()) {
            if ($form->get('save')->isClicked()) {
                $em = $this->getDoctrine()->getManager();
                $em->persist($category);
                $em->flush();
            }

            return $this->redirect($this->generateUrl('bxtr_admin_category_list'));
        }

        $title = null;
        $trans = $this->get('translator');
        if ( $add ) {
            $title = $trans->trans('Ent.BookCategory.AddNew');
        } else {
            $title = $trans->trans('Ent.BookCategory.EditExisting', array('%name%' => $category->getName()));
        }

        return $this->render('BXTRAdminBundle:Layout:Edit.html.twig', array(
            'form' => $form->createView(),
            'main_title' => $title
        ));
    }
}
